package demo.generate.Demo_SetField;

import java.io.FileOutputStream;
import java.io.IOException;

import jdk.internal.org.objectweb.asm.Type;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.RETURN;

/**
 * Created by zhangyanfei on 2018/10/18.
 *
 * @author zhangyanfei
 * @date 2018/10/18
 */
public class GenerateClass {
    public static void generateClass() throws IOException {
        ClassWriter cw = new ClassWriter(0);
        String className = "demo/generate/Demo_SetField/MyClass";
        //
        cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, className, null,
            "java/lang/Object", null);

        //创建属性
        {
            FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, "name", Type.getDescriptor(String.class), null, null);
            fv.visitEnd();
        }

        {
            FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, "user", Type.getDescriptor(String.class), null, null);
            fv.visitEnd();
        }
        //构造方法
        {
            MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            // this 入栈  var 本地变量索引
            mv.visitVarInsn(ALOAD, 0);
            // 常量入栈
            mv.visitLdcInsn("Tom");
            // 操作指令入栈
            mv.visitFieldInsn(Opcodes.PUTFIELD, className, "name", Type.getDescriptor(String.class));
            mv.visitInsn(RETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        // setName
        {
            MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setName",
                "(" + Type.getDescriptor(String.class) + ")V", null, null);
            // this 入栈
            mv.visitVarInsn(ALOAD, 0);
            // 入参入栈
            mv.visitVarInsn(ALOAD, 1);
            // 执行赋值
            mv.visitFieldInsn(Opcodes.PUTFIELD, className, "name", Type.getDescriptor(String.class));
            mv.visitInsn(Opcodes.RETURN);
            mv.visitMaxs(2, 2);
        }
        // getName
        {
            MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getName", "()" + Type.getDescriptor(String.class),
                null, null);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, className, "name", Type.getDescriptor(String.class));
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 1);
        }

        byte[] code = cw.toByteArray();
        FileOutputStream fos = new FileOutputStream(
            "/Users/zhangyanfei/workspace/hissy-common/src/test/java/demo/generate/Demo_SetField/MyClass.class");
        fos.write(code);
        fos.close();
    }
}
